﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using OpenQuarters.WebQuarters.Utils;
using System.Web.Mvc;
using System.IO;
using System.Data.Linq;

namespace OpenQuarters.WebQuarters.Core
{
    [Serializable]
    public partial class CMSPage : CMSEntity<CMSPage, long>, IComparable<CMSPage>
    {
        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty]
        public long json_PageId
        {
            get { return this.PageId; }
        }

        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty]
        public string json_LanguageId
        {
            get { return this.LanguageId ; }
        }

        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty]
        public string json_Reference
        {
            get { return this.Reference; }
        }

        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty] 
        public long json_ParentId
        {
            get { return this.ParentId.HasValue ? this.ParentId.Value : -1; }
        }

        [Newtonsoft.Json.JsonProperty]
        public CMSPageVersion json_LiveVersion
        {
            get { return this.LiveVersion; }
        }

        [Newtonsoft.Json.JsonProperty]
        public CMSPageVersion json_DraftVersion
        {
            get { return this.DraftVersion; }
        }

        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty]
        public string json_Url
        {
            get { return this.GetUrl(); }
        }

        public int Order
        {
            get
            {
                return this.CurrentVersion == null ? 0 : this.CurrentVersion.Order;
            }
        }

        private CMSPageCollection childPages = null;

        [Newtonsoft.Json.JsonProperty]
        public CMSPageCollection json_ChildPages
        {
            get
            {
                if (childPages == null)
                {
                    childPages = new CMSPageCollection(this.ChildPages.OrderBy(e => e.Order).ToList());
                }
                return childPages;
            }
            set
            {
                childPages = value;
            }
        }

        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty]
        public int json_ChildPagesCount
        {
            get { return json_ChildPages.Count; }
        }

        [Filterable, Orderable]
        [Newtonsoft.Json.JsonProperty]
        public string json_Title
        {
            get { return this.Title; }
        }

        private string languageId = "";

        public string LanguageId
        {
            get { return languageId; }
            set { languageId = value; }
        }

        private CMSPageVersion mockVersion = new CMSPageVersion();

        public CMSPageVersion MockVersion
        {
            get
            {
                return mockVersion;
            }
            set
            {
                this.mockVersion = value;
            }
        }

        public CMSPageVersion LiveVersion
        {
            get
            {
                return this.CMSPageVersions.FirstOrDefault(e => e.PageId == this.PageId && e.IsLive);
            }
        }

        public CMSPageVersion DraftVersion
        {
            get
            {
                return this.CMSPageVersions.FirstOrDefault(e => e.UserId == Core.User.Current.UserId);
            }
        }

        public static List<KeyValuePair<string, string>> OptionSource_Pages
        {
            get
            {
                var l = new List<KeyValuePair<string, string>>();
                optionSource_PagesRecurse(l, CMSPage.Pages[0], 1);
                return l;
            }
        }

        private static void optionSource_PagesRecurse(List<KeyValuePair<string, string>> l, CMSPage page, int level)
        {
            string indent = "";
            if (level > 1)
            {
                indent = indent.PadLeft(level, Char.Parse(">")) + " ";
            }
            l.Add(new KeyValuePair<string, string>(page.PageId.ToString(), indent + page.Title));

            page.json_ChildPages.ForEach(e => optionSource_PagesRecurse(l, e, level + 1));
        }

        public static CMSPageCollection Pages
        {
            get
            {
                return new CMSPageCollection(CMSPage.HomePage);
            }
        }

        public static CMSPageVersion Current
        {
            get { return ContextItem.GetItem("CMSPage.Current", () => CMSPage.HomePage.LiveVersion); }
            set { ContextItem.SetItem("CMSPage.Current", value); }
        }

        public static ViewPage<Core.CMSPageVersion> CurrentHandler
        {
            get
            {
                var r = ContextItem.GetItem<ViewPage<Core.CMSPageVersion>>("CMSPage.CurrentHandler", () => null);
                if (r == null)
                {
                    throw new Exception("CMSPage.CurrentHandler cannot be accessed before Views.Site.Index.OnPreInit");
                }
                return r;
            }
            set { ContextItem.SetItem("CMSPage.CurrentHandler", value); }
        }

        //public CMSPage ParentPage
        //{
        //    get
        //    {
        //        return this.ParentId.HasValue ? CMSPage.Load(this.ParentId.Value) : null;
        //    }
        //}

        public static CMSPage HomePage
        {
            get
            {
                var home = Table.FirstOrDefault(e => e.ParentId == null);
                if (home == null)
                {
                    Role.BasicSetup();
                    User.BasicSetup();

                    home = new CMSPage()
                    {
                        ParentId = null,
                        Reference = "HOME"
                    }.Save();

                    home.EnsureDraftVersion("Home").MakeLive();

                    var id = home.PageId.ToString();

                    Permissions.CMSPage.View.SetValue(id).SetRoleId(Role.GuestRoleId).Save();

                    Permissions.CMSPage.View.SetValue(id).SetRoleId(Role.UserRoleId).Save();

                    Permissions.CMSPage.View.SetValue(id).SetRoleId(Role.EditorRoleId).Save();
                    Permissions.CMSPage.Edit.SetValue(id).SetRoleId(Role.EditorRoleId).Save();
                    Permissions.CMSPage.Create.SetValue(id).SetRoleId(Role.EditorRoleId).Save();
                    Permissions.CMSPage.Delete.SetValue(id).SetRoleId(Role.EditorRoleId).Save();

                    Permissions.CMSPage.View.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Edit.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Create.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Delete.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Approve.SetValue(id).SetRoleId(Role.AdminRoleId).Save();

                    Permissions.CMSPage.View.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Edit.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Create.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Delete.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    Permissions.CMSPage.Approve.SetValue(id).SetRoleId(Role.AdminRoleId).Save();
                    
                    Permissions.CMSPage.View.SetValue(id).SetRoleId(Role.SuperAdminRoleId).Save();
                    Permissions.CMSPage.Edit.SetValue(id).SetRoleId(Role.SuperAdminRoleId).Save();
                    Permissions.CMSPage.Create.SetValue(id).SetRoleId(Role.SuperAdminRoleId).Save();
                    Permissions.CMSPage.Delete.SetValue(id).SetRoleId(Role.SuperAdminRoleId).Save();
                    Permissions.CMSPage.Approve.SetValue(id).SetRoleId(Role.SuperAdminRoleId).Save();
                }
                return home;
            }
        }

        public static CMSPage LoginPage
        {
            get
            {
                var login = Table.FirstOrDefault(e => e.Reference == "LOGIN");
                if (login == null)
                {
                    login = new CMSPage()
                    {
                        ParentId = HomePage.PageId,
                        Reference = "LOGIN"
                    }.Save();

                    login.EnsureDraftVersion("Login").MakeLive();
                    login.ReplicatePermissions(HomePage);
                }
                return login;
            }
        }

        public override string ToString()
        {
            return "'" + this.Title + "' (ID " + this.PageId.ToString() + ")";
        }

        public static CMSPage LoadByReference(string Reference)
        {
            return Table.FirstOrDefault(e => e.Reference == Reference);
        }

        public CMSPageVersion EnsureDraftVersion(string Title)
        {
            return this.DraftVersion ?? new CMSPageVersion()
            {
                PageId = this.PageId,
                UserId = Core.User.Current.IsAuthenticated ? Core.User.Current.UserId : null,
                CMSPage = this,
                Title = Title,
                Template = this.CurrentVersion != null ? this.CurrentVersion.Template : "Default",
                Keywords = this.CurrentVersion != null ? this.CurrentVersion.Keywords : "",
                Description = this.CurrentVersion != null ? this.CurrentVersion.Description : "",
                Definition = this.CurrentVersion != null ? this.CurrentVersion.Definition : "{\"Areas\":[]}"

            }.Save();
        }

        public void EnsureMockVersion(string Title)
        {
            this.MockVersion = new CMSPageVersion()
            {
                PageId = 0,
                UserId = Core.User.Current.IsAuthenticated ? Core.User.Current.UserId : null,
                CMSPage = this,
                Title = Title,
                Template = this.CurrentVersion != null ? this.CurrentVersion.Template : "Default",
                Keywords = this.CurrentVersion != null ? this.CurrentVersion.Keywords : "",
                Description = this.CurrentVersion != null ? this.CurrentVersion.Description : "",
                Definition = this.CurrentVersion != null ? this.CurrentVersion.Definition : "{\"Areas\":[]}"
            };
        }

        public override System.Linq.Expressions.Expression<Func<CMSPage, bool>> GetIDSelector(long ID)
        {
            return e => e.PageId == ID;
        }

        public override long GetKey(CMSPage Entity)
        {
            return Entity.PageId;
        }

        public override DataLoadOptions GetLoadOptions()
        {
            var r = new DataLoadOptions();
            r.LoadWith<CMSPage>(e => e.CMSPageVersions);
            return r;
        }

        public string GetUrl()
        {
            var bestUrl = this.Urls.FirstOrDefault(e => e.LanguageId == Language.Current.LanguageId);
            if (bestUrl == null)
            {
                bestUrl = this.Urls.FirstOrDefault();
            }
            if (bestUrl == null)
            {
                bestUrl = new Url()
                {
                    PageUrl = ""
                };
            }
            return "/site/" + bestUrl.PageUrl;
        }

        public void ReplicatePermissions(CMSPage replicatePage)
        {
            var replicatePermissions = Permission.Table
                .Where(e => e.Value == replicatePage.PageId.ToString() && e.Name.StartsWith("CMSPage."))
                .ToList();

            foreach (var p in replicatePermissions)
            {
                new Permission()
                {
                    Name = p.Name,
                    Value = this.PageId.ToString(),
                    RoleId = p.RoleId
                }.Save();
            }
        }

        public static CMSPageVersion GetVersionForUser(string idOrUrl)
        {
            if (idOrUrl == null || idOrUrl.Length == 0)
            {
                idOrUrl = CMSPage.HomePage.PageId.ToString();
            }
            else if (!GeneralUtils.IsNumeric(idOrUrl))
            {
                if (idOrUrl.StartsWith("http://") || idOrUrl.StartsWith("https://"))
                {
                    idOrUrl = idOrUrl.Substring(idOrUrl.IndexOf("//") + 2);
                    idOrUrl = idOrUrl.Substring(idOrUrl.IndexOf("/") + 1);
                    idOrUrl = idOrUrl.Substring(idOrUrl.IndexOf("/") + 1);
                }
                else if (idOrUrl.StartsWith("/site/"))
                {
                    idOrUrl = idOrUrl.Substring(6);
                }

                if (idOrUrl == "/site/" || idOrUrl == "/site" || idOrUrl == "site")
                {
                    idOrUrl = CMSPage.HomePage.PageId.ToString();
                }
                else
                {
                    if (idOrUrl.EndsWith("/"))
                    {
                        idOrUrl = idOrUrl.Substring(0, idOrUrl.Length - 1);
                    }
                    if (idOrUrl.StartsWith("/"))
                    {
                        idOrUrl = idOrUrl.Substring(1);
                    }
                    var idTest = idOrUrl;
                    if (idTest.Contains("/"))
                    {
                        idTest = idTest.Substring(0, idTest.IndexOf("/"));
                    }
                    var urls = Core.Url.Table.Where(e => e.PageUrl.StartsWith(idTest)).ToList();

                    Url url = null;
                    foreach (var u in urls)
                    {
                        if (u.PageUrl == idOrUrl)
                        {
                            url = u;
                            break;
                        }
                    }

                    List<string> urlParts = idOrUrl.Split('/').ToList();

                    if (url == null && urls.Count > 0)
                    {
                        FriendlyDictionary<Url, int> urlRanking = new FriendlyDictionary<Url, int>();
                        foreach (Url eachUrl in urls)
                        {
                            foreach (string urlPart in urlParts)
                            {
                                if (eachUrl.PageUrl.Contains("/" + urlPart))
                                {
                                    urlRanking[eachUrl]++;
                                }
                            }
                        }

                        url = urlRanking.ToList().OrderByDescending(kv => kv.Value).Select(kv => kv.Key).FirstOrDefault();                        
                    }

                    if (url == null && urls.Count > 0)
                    {

                        url = urls[0];
                    }

                    if (url != null)
                    {
                        idOrUrl = url.PageId.ToString();
                    }
                }
            }

            // If user is logged in, display their draft by default
            var page = CMSPage.Load(Convert.ToInt64(idOrUrl));
            var version = (Core.User.Current.IsAuthenticated ? page.CMSPageVersions.FirstOrDefault(e => e.UserId == Core.User.Current.UserId) : page.LiveVersion);

            if (version == null)
            {
                version = page.LiveVersion;
            }

            return version;
        }

        public static List<string> Templates
        {
            get
            {
                var r = new List<string>();

                var files = Directory.GetFiles(Oracle.Context.Server.MapPath("~/Areas/Site/Views/Templates/"), "*.aspx")
                    .ToList();
                foreach (var e in files)
                {
                    if (!e.StartsWith("."))
                    {
                        r.Add(e.Remove(0, e.LastIndexOf("\\") + 1).Replace("_", " ").Replace(".aspx", ""));
                    }
                }

                return r;
            }
        }

        public CMSPageVersion CurrentVersion
        {
            get
            {
                return this.DraftVersion ?? this.LiveVersion ?? this.MockVersion;
            }
        }

        public string Title
        {
            get
            {
                return this.CurrentVersion == null ? "" : this.CurrentVersion.Title;
            }
            set
            {
                if (this.CurrentVersion != null)
                {
                    this.CurrentVersion.Title = value;
                }
            }
        }

        public string GetLinkHTML()
        {
            return this.CurrentVersion == null ? "" : "<a href=\"" + this.GetUrl() + "\"" + (this.CurrentVersion.NoFollow ? " rel=\"nofollow\"" : "") + ">" + this.Title + @"</a>";
        }

        #region IComparable<CMSPage> Members

        public int CompareTo(CMSPage other)
        {
            if (this.CurrentVersion != null && other.CurrentVersion != null)
            {
                return this.CurrentVersion.Order.CompareTo(other.CurrentVersion.Order);
            }
            return 0;
        }

        #endregion
    }
}
